#pragma once

#include "Sem.hpp"
#include <vector>
#include "Mutex.hpp"

using namespace MutexModule;
static const unsigned int defaultnum = 5;

template<typename T>
class RingQueue
{
public:
    RingQueue(unsigned int cap = defaultnum)
        : _v(cap, 0), _cap(cap), _pstep(0), _cstep(0), _sem_blank(cap), _sem_data(0)
    {
    }
    ~RingQueue()
    {
    }
    void EnQueue(const T &data)
    {
        // 生产者
        _sem_blank.P();
        {
            // 先竞争信号量，再竞争锁，效率更高
            MutexGuard mutexguard(_pmutex);
            // 1.执行_pstep位置的任务
            _v[_pstep] = data;
            // 2.迭代
            _pstep++;
            // 3.维持环形队列结构
            _pstep %= _cap;
        }
        _sem_data.V();
    }
    void Pop(T *data)
    {
        // 消费者
        _sem_data.P();
        {
            MutexGuard mutexguard(_cmutex);
            *data = _v[_cstep];
            _cstep++;
            _cstep %= _cap;
        }
        _sem_blank.V();
    }

private:
    std::vector<T> _v; // 数组模拟环形队列
    int _cap;            // 环形队列容量

    int _pstep; // 生产者下标
    int _cstep; // 消费者下标

    Sem _sem_blank; // 空位置信号量，生产者资源
    Sem _sem_data;  // 数据信号量，消费者资源

    Mutex _pmutex; // 生产者间的互斥锁
    Mutex _cmutex; // 消费者间的互斥锁
};